/**
 * @description: 封装二叉搜索树
 * 节点中: right > root > left
 * @return {*}
 */
function BinarySerachTree () {
    function Node (key) {  
        this.key = key;
        this.rigth = null;
        this.left = null;
    }

    // 属性
    this.root = null;

    // 方法
    // 1 插入数据:1.1对外暴露
    BinarySerachTree.prototype.insert = function (key) {  
        let newNode = new Node (key);

        // 判断根节点是否有值
        if (this.root == null) {
            this.root = newNode
        } else {
            this.insertNode(this.root, newNode)
        }
    }

    // 1.2 封装递归比较
    BinarySerachTree.prototype.insertNode = function (node, newNode) {  
        if (node.key > newNode.key) {
            // 向左查找
            if (node.left == null) {
                node.left = newNode
            } else {
                this.insertNode(node.left, newNode)
            }
        } else {
            // 向右查找
            if (node.rigth == null) {
                node.rigth = newNode
            } else {
                this.insertNode(node.rigth, newNode)
            }
        }
    }

    // 2 先序遍历 root -> left -> right
    // handler为遍历处理函数
    BinarySerachTree.prototype.preOrderTraversal = function (handler) {
        // 传入回调函数
        this.preOrderTraversalNode(this.root, handler);
    }

    // 2.1 先序遍历的回调函数
    BinarySerachTree.prototype.preOrderTraversalNode = function (node, handler) {  
        // 节点不为空,则进行递归遍历处理
        if (node != null) {
            handler(node.key);

            // 递归处理左子节点
            this.preOrderTraversalNode(node.left, handler)

            // 递归处理右子节点
            this.preOrderTraversalNode(node.rigth, handler)
        }
    }

    // 3 中序遍历 left -> root -> right
    BinarySerachTree.prototype.midOrderTraversal = function (handler) {  
        // 传入回调函数
        this.midOrderTraversalNode(this.root, handler)
    }
    BinarySerachTree.prototype.midOrderTraversalNode = function (node, handler) {  
        // 判断左节点是否为空
        if (node != null) {
            // 传入左节点递归
            this.midOrderTraversalNode (node.left, handler);

            // 中间节点
            handler(node.key);

            // 右边节点递归
            this.midOrderTraversalNode (node.rigth, handler)
        }
    }

    // 4 后序遍历 left -> right -> root
    BinarySerachTree.prototype.postOrderTraversal = function (handler) {  
        this.postOrderTraversalNode(this.root, handler);
    }

    BinarySerachTree.prototype.postOrderTraversalNode = function (node, handler) {  
        // 判断是否为空
        if (node != null) {
            // 递归左节点
            this.postOrderTraversalNode(node.left, handler);
            // 递归右节点
            this.postOrderTraversalNode(node.rigth, handler);

            // 提取节点
            handler(node.key)
        }
    }

    // 5 寻找最值
    BinarySerachTree.prototype.min = function () {  
        let minNode = this.root;
        while (minNode.left != null) {
            minNode = minNode.left
        }
        return minNode.key
    }

    BinarySerachTree.prototype.max = function () {  
        let maxNode = this.root;
        while (maxNode.rigth != null) {
            maxNode = maxNode.rigth
        }
        return maxNode.key
    }

    // 6 搜索某一个key
    BinarySerachTree.prototype.search = function (key) {  
        // 获取根节点
        let node = this.root;

        // 循环搜索
        while (node != null) {
            if (key == node.key) {
                return node
            }
            else if (key > node.key) {  // 二分法
                node = node.rigth;
            }else {
                node = node.left
            }
        }
        return false
    }

    // 7 * 二叉搜索树的删除
    BinarySerachTree.prototype.remove = function (key) {
        // 定义属性遍量
        let current = this.root;
        let parentNode = null;
        let isLeftChild = false;

        // 判断是否存在
        if (current == null) {
            return false
        }

        // 7.1 搜索删除节点
        while (current.key != key) {
            parentNode = current;
            if (key > current.key) {
                isLeftChild = false;
                current = current.rigth;
            } else {
                isLeftChild = true;
                current = current.left;
            }
        }

        // 7.2 没有找到,不删除
        if (current == null) {
            return false
        }

        // 7.3 删除叶子节点
        if (current.left == null && current.rigth == null) {
            // 如果是根节点
            if (current == this.root) {
                this.root = null
            } else if (isLeftChild) {
                parentNode.left = null
            } else {
                parentNode.rigth = null
            }
        }

        // 7.4 删除有一个子节点的节点
        else if (current.left == null) {
            // 判断是否为根节点
            if (current == this.root) {
                this.root = current.rigth;
            }
            else if (isLeftChild) {
                parentNode.left = current.rigth;
            } else {
                parentNode.rigth = current.rigth;
            }
        } else if (current.rigth == null) {
            if (current == this.root) {
                this.root = current.left
            }
            else if (isLeftChild) {
                parentNode.left = current.left;
            } else {
                parentNode.rigth = current.left;
            }
        }

        // 7.5 删除有2个子节点的节点
        else {
            // 获取后继节点
            let successor = this.getsuccessor(current);
            // 判断是否为根节点
            if (current == this.root) {
                this.root = successor;
            } else if(isLeftChild) {
                parentNode.left = successor;
            } else {
                parentNode.rigth = successor;
            }

            // 将删除节点的左子树 等于 current.left
            successor.left = current.left;
        }

    }

    // 7.6 找后继的方法 --> 寻找右节点中, 最小的左子节点(该节点可能存在右子节点)
    BinarySerachTree.prototype.getsuccessor = function (delNode) {  
        // 定义属性
        let current = delNode.rigth;
        let successor = delNode;
        let successorParent = delNode;

        // 向右进行后继查找, 最小的子节点
        while (current != null) {
            successorParent = successor;
            successor = current;
            current = current.left;
        }

        // 判断寻找的后继节点是否直接就是delNode.rigth
        if (successor != delNode.rigth) {
            successorParent.left = successor.rigth;  // 可能存在 右子节点
            successor.rigth = delNode.rigth // 代替被删节点
        }

        return successor
    }


}

// 测试代码
let bst = new BinarySerachTree();
bst.insert(11);
bst.insert(7);
bst.insert(15);
bst.insert(5);
bst.insert(3);
bst.insert(9);
bst.insert(8);
bst.insert(10);
bst.insert(13);
bst.insert(12);
bst.insert(25);
bst.insert(18);
bst.insert(20);
bst.insert(14);
bst.insert(6);

// 测试先序遍历
let resultSearch = "先序遍历: ";
bst.preOrderTraversal(function (key) {
    resultSearch += key + " ";
})
console.log(resultSearch);

// 测试中序遍历
resultSearch = "中序遍历: ";
bst.midOrderTraversal(function (key) {
    resultSearch += key + " ";
})
console.log(resultSearch);

// 测试后序遍历
resultSearch = "后序遍历: ";
bst.postOrderTraversal(function (key) {
    resultSearch += key + " ";
})
console.log(resultSearch);

// 测试最值
console.log(bst.min());
console.log(bst.max());

// 测试搜索
console.log(bst.search(6));
console.log(bst.search(999));

console.log("--------------------------------------");

// 测试删除节点
bst.remove(9);
bst.remove(7);
bst.remove(15);

// 测试后序遍历2.0
resultSearch = "后序遍历2.0: ";
bst.postOrderTraversal(function (key) {
    resultSearch += key + " ";
})
console.log(resultSearch);
